# -*- coding: utf-8 -*-

"""
This implements the OpenGL widget
"""
import copy
        
from PyQt4 import QtOpenGL
from OpenGL import GL

import curve
from mathematic import Vector
 
a = 0
class Drawer(object):
    """
        This class is responsible by draw all elements how: curve and points.
    """
    
    
    def __init__ (self):
        """
            The atribute curve is a composition. This object contain attibutes 
            and methods to draw a curve.
        """
        self.point_size = 5
        
        self.density = 1
        
        # Colors
        self.r = 0
        self.g = 0
        self.b = 0
        
        # list of points used in drawPoints
        self.point_list = []
        
        # Points that determine a line
        self.point1 = self.point2 = Vector( [0.0, 0.0, 0.0] )
        
        self.bbox = []
        self.bbox_list = []

    def drawLine(self):
        """
            Drawer a line that contain the points of attribute point1 and point2.
            
            The color of curve is determined by combination of colors 
            represented by parameters r (red), g (green) and b (blue).
        """
        GL.glColor3f(self.r, self.g, self.b)

        GL.glBegin(GL.GL_LINES)
        GL.glVertex3fv(self.point1)
        GL.glVertex3fv(self.point2)
        GL.glEnd()


    def drawPoint(self):
        """
            Drawer the point of the attribute point1.
            
            The color of curve is determined by combination of colors 
            represented by parameters r (red), g (green) and b (blue).
        """
        GL.glColor3f(self.r, self.g, self.b)
        GL.glPointSize(self.point_size)
        GL.glBegin(GL.GL_POINTS)
        GL.glVertex3fv(self.point1)
        GL.glEnd()
        
    def drawPoints(self):
        """
            Drawer a set of the points contained in attribute point_list.
            
            The color of curve is determined by combination of colors 
            represented by parameters r (red), g (green) and b (blue).
        """
        for i in range( len(self.point_list) ):
	        self.point1 = self.point_list[i]
	        self.drawPoint()

    def drawBox(self):
        """
            Drawer a box represented by attribute box
            
            The color of curve is determined by combination of colors 
            represented by parameters r (red), g (green) and b (blue).
        
        x4------x5
        |   \   |  \
        |    x0-|----x1
        |    |  |    |   
        x7---|-x6    |
             x3------x2
        
        """
       
        x0 = self.bbox.origin
        x1 = self.bbox.origin + [self.bbox.width, 0, 0]
        x2 = x1 + [0, self.bbox.height, 0]
        x3 = self.bbox.origin + [0, self.bbox.height, 0]

        self.point1 = x0; self.point2 = x1; self.drawLine()
        self.point1 = x1; self.point2 = x2; self.drawLine()
        self.point1 = x2; self.point2 = x3; self.drawLine()
        self.point1 = x3; self.point2 = x0; self.drawLine()                
            
    def drawBoxList(self):
        for box in self.bbox_list:
            self.bbox = box
            self.drawBox()

    def drawPatchCurve(self):
        """
            Drawer a curve that contain the points of the parameter point_list.
            
            The color of curve is determined by combination of colors 
            represented by parameters r (red), g (green) and b (blue).
        """
        GL.glColor3f(self.r, self.g, self.b)
        GL.glBegin(GL.GL_LINE_STRIP)
        for i in range(10):
            GL.glVertex3fv(self.point_list[i])
        GL.glEnd()    

    
class GlWidget (QtOpenGL.QGLWidget):
    """
        A simple OpenGL pane
    """
    
    def __init__ (self, parent=None):
        """
            TODO
        """
        super (GlWidget, self).__init__(parent)
       
        # Used to create a new curve
        self.creating = False
        self.control_point_list = []
        
        # Used to manipulate the curve
        self.drag = False
        
        self.window_left = None
        self.window_top = None
        self.window_right = None
        self.window_bottom = None

        self.viewport_left = None
        self.viewport_top = None
        self.viewport_width = None
        self.viewport_height = None
        
        self.painter = Painter()
        
        self.curve_point = []
        self.manipulate_point = []
        self.a = 0
        

        
    def paintGL(self):
        """
            This method is responsible to Draw in GLWidget.
            
            This is called automatically when the widget is created. After 
            this is called virtually by method glDraw.
            
            The painter is modified according the FactoryPainter. So in 
            different moment this method can have a different behavior
        """

        GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT)
        self.painter.paint()
        print "hello"
        GL.glFlush()
     
    def resizeGL (self, width, height):
        """
            This method calculate the coordinates of window
        """
        self.viewport_left = 0
        self.viewport_top = 0
        self.viewport_width = width
        self.viewport_height = height

        # Mudar
        x0 = -5.0
        x1 = 5.0
        y0 = 5.0
        y1 = -5.0

        if (x1 - x0) <= (y1 - y0):
            self.window_left = x0 * ((x1 - x0) / (y0 - y1)) * (height / width)
            self.window_right = x1 * ((x1 - x0) / (y0 - y1)) * (height / width)
            self.window_bottom = y1 * height / width
            self.window_top = y0 * height / width
        else:
            self.window_left = x0 * ((y0 - y1) / (x1 - x0)) * (width / height)
            self.window_right = x1 * ((y0 - y1) / (x1 - x0)) * (width / height)
            self.window_bottom = y1
            self.window_top = y0
        
        GL.glViewport( self.viewport_left,  self.viewport_top, 
                       self.viewport_width, self.viewport_height)
        
        GL.glMatrixMode(GL.GL_PROJECTION)
        GL.glLoadIdentity()

        GL.glOrtho( self.window_left,   self.window_right, 
                    self.window_bottom, self.window_top, -5.0, 5.0)

        GL.glMatrixMode(GL.GL_MODELVIEW)
        GL.glLoadIdentity()
        self.glDraw()

    def mousePressEvent(self, event):
        horizontal = self.window_right - self.window_left
        vertical = self.window_bottom - self.window_top
        self.press_point = Vector( 
                 [(event.x()*horizontal/self.viewport_width)-(horizontal/2.0),
                  (event.y()*vertical/self.viewport_height)-(vertical/2.0),0.0])


    def mouseMoveEvent(self, cursor):
        """
            When click on GLWidget this method is automatically called.
        """
        self.a += 1
        

        mainwindow = self.parent().parent().parent()

            
        if (mainwindow.manipulation_curve_enabled.isEnabled() and
                           mainwindow.manipulation_curve_enabled.isChecked() ):
            
            x = cursor.pos().x()
            y = cursor.pos().y()
            horizontal = self.window_right - self.window_left
            vertical = self.window_bottom - self.window_top
            point = Vector( 
                     [(x*horizontal/self.viewport_width)-(horizontal/2.0),
                      (y*vertical/self.viewport_height)-(vertical/2.0),0.0])


            self.painter.curve.manipulateCurve(self.press_point, point )
            print self.a
            print self.press_point
            print point
            self.press_point = point
            print self.press_point
            print "\n\n"

            self.painter.curve.definePatch(0)

            self.glDraw()    
            

    
    def mouseReleaseEvent(self, event):
        """
            When click on GLWidget this method is automatically called.
        """
        horizontal = self.window_right - self.window_left
        vertical = self.window_bottom - self.window_top
        point = Vector( 
                 [(event.x()*horizontal/self.viewport_width)-(horizontal/2.0),
                  (event.y()*vertical/self.viewport_height)-(vertical/2.0),0.0])
        self.release_point = point
        

        mainwindow = self.parent().parent().parent()

        if self.creating:
            self.control_point_list.append(point)
            mainwindow.browser.append(str(point))            
            self.painter.drawer.point_list = []
            self.painter.drawer.point_list = self.control_point_list
            r = float( mainwindow.color_points.red()   ) / 255
            g = float( mainwindow.color_points.green() ) / 255 
            b = float( mainwindow.color_points.blue()  ) / 255
            self.painter.setColor(r, g, b, "Points")

        if (mainwindow.manipulation_curve_enabled.isEnabled() and
                           mainwindow.manipulation_curve_enabled.isChecked() ):
            self.painter.drawer.point1 = self.press_point
            self.painter.drawer.point2 = self.release_point
            
            self.painter.r = 1.0
            self.painter.g = 1.0
            self.painter.b = 0.0
            self.painter.curve.manipulateCurve(self.press_point, 
                                               self.release_point )
            self.painter.curve.definePatch(0)

            self.glDraw()    


        self.glDraw()
#        self.drag = False


class FactoryPainter(object):
    def choicePainter(self, choice):
        painter = Painter()
        if choice == "blank":
            # if choice is blank the object is a Painter
            pass
        elif choice == "curve":
            painter = PaiterCurve()
            
        return painter 
        
        
# All class below follow a standart necessary to a desing pattern Chain of 
# Responsibility. The instanciation of Painter objects is done for the design 
# pattern Factory.
# So all painters inherit of the class Painter and have a method paint.
class Painter(object):
    def __init__(self, previous = None):
        self.prev = previous
        self.drawer = Drawer()
        
    def paint(self):
        """
            This method pass because painter objects don't paints.
            
            Only the objects of class that inherits of Painter paints.
        """
        pass

    def setColor(self, r, g, b, type_painter):
        pass


class PainterPoints(Painter):
    def __init__(self, prev, color = None):
        super(PainterPoints, self).__init__(prev)
        self.color_points = (0.0, 0.0, 0.0)  
    
    def paint(self):
        self.drawer.drawPoints()
        
        if self.prev:
            self.prev.paint()
            
    def setColor(self, r, g, b, type_painter):
        if type_painter == "Points":
            self.drawer.r = r
            self.drawer.g = g
            self.drawer.b = b
        else:
            self.prev.setColor(r, g, b, type_painter)

class PainterCurve(Painter):
    def __init__(self, prev):
        super(PainterCurve, self).__init__(prev)
        self.opened = True
        self.curve = None    
        self.curve_color = (0.0, 0.0, 0.0)
        
    def paint(self):
        if self.opened:
            quantity_patch = len(self.curve.cp_list) - 3
        else:
            quantity_patch = len(self.curve.cp_list)

        self.curve.definePatch(0)
        for i in range(quantity_patch):
            self.drawer.point_list = self.curve.generatePatch()
            self.curve.nextPatch()
            self.drawer.drawPatchCurve()

          
        if self.prev:
            self.prev.paint()

    def setColor(self, r, g, b, type_painter):
        if type_painter == "Curve":
            self.drawer.r = r
            self.drawer.g = g
            self.drawer.b = b
        else:
            self.prev.setColor(r, g, b, type_painter)
